package com.ql.util;

import com.google.common.collect.Lists;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by Administrator on 2016/12/31.
 * http://www.cnblogs.com/GYoungBean/p/4301557.html
 */
public class LambdaDemo {

    public static void main(String[] args) {

//        收集器（Collectors）
 /*       collect()操作会把其接收的元素聚集（aggregate）到一起（这里是List），
         collect()方法的参数则被用来指定如何进行聚集操作。在这里我们使用toList()以把元素输出到List中*/
        /* Collectors toList() returns a Collector that
                accumulates the input elements into a new List.*/
                Stream<String> s = Stream.of("a","b","c");
                    List<String> names1 = s
                        .collect(Collectors.toList());//
                    System.out.println(names1);


/*使用Stream.flatMap()得到一个歌曲流，然后用Pattern.splitAsStream把每首歌曲的标题打散成词流；
接下来我们用groupingBy和String.toUpperCase对这些词进行不区分大小写的分组，
最后使用counting()收集器计算每个词出现的次数*/
    /*    Pattern pattern = Pattern.compile("\\s+");
        Map<String, Integer> wordFreq =tracks.stream()
                  .flatMap(t -> pattern.splitAsStream(t.name)) // Stream<String>
                  .collect(Collector.groupingBy(s -> s.toUpperCase(),
                                      counting()));

    Map<Artist, List<Track>> favsByArtist =
        tracks.stream()
              .filter(t -> t.rating >= 4)
              .collect(Collectors.groupingBy(t -> t.artist));
            /***
              flatMap接收一个返回流（这里是歌曲标题里的词）的函数。它利用这个函数将输入流中的每个元素转换为对应的流，然后把这些流拼接到一个流中。
              所以上面代码中的flatMap会返回所有歌曲标题里面的词，接下来我们不区分大小写的把这些词分组，并把词频作为值（value）储存。
              Collectors类包含大量的方法，这些方法被用来创造各式各样的收集器，以便进行查询、列表（tabulation）和分组等工作，
              当然你也可以实现一个自定义Collector。
*/

       /* (Type1 param1, Type2 param2, ..., TypeN paramN) -> {
          statment1;
          statment2;
          //.............
          return statmentM;
        }*/
        List<String> names = new ArrayList<String>();
        names.add("TaoBao");
        names.add("ZhiFuBao");

        List<String> lowercaseNames = names.stream().map((name) -> {
            return name.toUpperCase();
        }).collect(Collectors.toList());

        System.out.println("--------------------------------\n");
        lowercaseNames = names.stream().map(String::toLowerCase)
                                        .collect(Collectors.toList());
        ListUtils.printList(lowercaseNames);

        //Java8中Lambda表达式的10个例子
//        例1 用Lambda表达式实现Runnable接口
        new Thread(() -> System.out.println("in java8,lambda expression rocks.")).start();

//        (参数) -> 表达式
//        (参数) -> 语句
//        (参数) -> { 语句 }
        System.out.println("--------------------------------\n");
        List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
        features.forEach(n -> System.out.println(n));
//        例1 方法引用由::(双冒号)操作符来完成
        System.out.println("方法引用由::(双冒号)操作符来完成");
        features.forEach(System.out::println); //

        //例4 使用Lambda表达式和函数式接口Predicate -断定
        predicate_demo();
        System.out.println("\n Map和Reduce的例子--------------------------------\n");
//       例6 Map和Reduce的例子
        List<Double>  costBeforeTax = Arrays.asList(Double.valueOf(100), Double.valueOf(200));
        costBeforeTax.stream().map(( cost)-> cost + (.12 * cost))
                            .forEach(System.out::print);
//        例7 用filter创建一个字符串List
        System.out.println("用filter创建一个字符串List--------------------------------\n");
        List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
        List<Integer> distinct = numbers.stream().map( i ->i*i)
                                .distinct().collect(Collectors.toList());
        System.out.printf("Original List : %s, Square Without duplicates : %s %n", numbers, distinct);
        System.out.println(distinct);

//        List<String>  d= features.stream().map(String::toLowerCase).collect(Collectors.toList());

        System.out.println("================\n");
        List<Integer> values = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
        List<Integer> value1  =values.stream().filter(i->i > 2 ).sorted().collect(Collectors.toList());
        System.out.println(value1);//[3, 3, 4, 4, 7, 9, 10]

        //这段代码就是先获取一个无限长度的正整数集合的Stream，然后取出前10个打印
        Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);


        List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
        //sum is:36
        System.out.println("sum is:"+nums.stream().filter(num -> num != null).
                    distinct().mapToInt(num -> num * 2).
                    peek(System.out::println).skip(2).limit(4).sum());


        List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
        //ints sum is:55
        System.out.println("ints sum is:" + ints.stream().reduce((sum, item) ->sum + item).get());

        //它允许用户提供一个循环计算的初始值，如果Stream为空，就直接返回该值。如下 0不停在叠加
        System.out.println("ints sum 0 is:" + ints.stream().reduce(0, (sum, item) -> sum + item));


        /*Arrays.stream(enclosingInfo.getEnclosingClass().getDeclaredMethods())
                     .filter(m -> Objects.equal(m.getName(), enclosingInfo.getName()))
                     .filter(m -> Arrays.equal(m.getParameterTypes(), parameterClasses))
                     .filter(m -> Objects.equals(m.getReturnType(), returnType))
                     .findFirst()
                     .orElseThrow(() -> new InternalError("Enclosing method not found"));*/

    }


    ////例4 使用Lambda表达式和函数式接口Predicate -断定
    public static void predicate_demo(){
        List  languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
        System.out.println("Languages which starts with J :");
        filter(languages, ( str)->str.toString().startsWith("J"));
        System.out.println("Languages which ends with a ");
        filter(languages, (str)->str.toString().endsWith("a"));
        System.out.println("Print all languages :");
        filter(languages, (str)->true);
        System.out.println("Print no language : ");
        filter(languages, (str)->false);
        System.out.println("Print language whose length greater than 4:");
        filter(languages, ( str)->str.toString().length() > 4);

    }
    //Predicate允许组合两个以上的条件，它提供了类似于逻辑与和或的操作and(),or()和xor()
    public static void filter(List  names, Predicate condition) {//断定
        names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
        System.out.println(name + " ");

// /Predicate允许组合两个以上的条件，它提供了类似于逻辑与和或的操作and(),or()和xor()
            Predicate<String> startsWithJ = (n) -> n.startsWith("J");
            Predicate<String> fourLetterLong = (n) -> n.length() == 4;
            names.stream().filter(startsWithJ.and(fourLetterLong)).forEach(
                    (n) -> System.out.print("\nName, which starts with 'J' and four letter long is : " + n));

    });
    }


    // jdk8 和7的对比写法
    public  void test_lambda(){//收集器（Collectors）
      /*  List<Album> favs = new ArrayList<>();
        for (Album album : albums) {
          boolean hasFavorite = false;
          for (Track track : album.tracks) {
            if (track.rating >= 4) {
              hasFavorite = true;
              break;
            }
          }
          if (hasFavorite)
            favs.add(album);
        }
        Collections.sort(favs, new Comparator<Album>() {
          public int compare(Album a1, Album a2) {
            return a1.name.compareTo(a2.name);
          }
        });*/
//     我们可以用流操作来完成上面代码中的三个主要步骤

/*List<Album> sortedFavs =
    albums.stream()
          .filter(a -> a.tracks.anyMatch(t -> (t.rating >= 4)))
          .sorted(Comparator.comparing(a -> a.name))
          .collect(Collectors.toList());*/


       /* for (Method method : enclosingInfo.getEnclosingClass().getDeclaredMethods()) {
          if (method.getName().equals(enclosingInfo.getName())) {
            Class< ? >[] candidateParamClasses = method.getParameterTypes();
            if (candidateParamClasses.length == parameterClasses.length) {
              boolean matches = true;
              for (int i = 0; i < candidateParamClasses.length; i += 1) {
                if (!candidateParamClasses[i].equals(parameterClasses[i])) {
                  matches = false;
                  break;
                }
              }

              if (matches) { // finally, check return type
                if (method.getReturnType().equals(returnType)) {
                  return method;
                }
              }
            }
          }
        }
        throw new InternalError("Enclosing method not found");*/
      //对比上面写法
        /*Arrays.stream(enclosingInfo.getEnclosingClass().getDeclaredMethods())
                     .filter(m -> Objects.equal(m.getName(), enclosingInfo.getName()))
                     .filter(m -> Arrays.equal(m.getParameterTypes(), parameterClasses))
                     .filter(m -> Objects.equals(m.getReturnType(), returnType))
                     .findFirst()
                     .orElseThrow(() -> new InternalError("Enclosing method not found"));*/

    }

}
